import random
import time
from os import name

import requests
from apis.models import School
from apis.models.group import Group
from celery import Task, exceptions, shared_task
from django.db.models import Q
from django.http import JsonResponse
from django.http.response import Http404
from djco import base, celery
from djco.base.base_api import BaseApi
from djco.celery import app

"""
    celery 任务 供其它模块调用
    参考文档
    https://docs.celeryproject.org/en/stable/reference/celery.app.task.html#celery.app.task.Task.retry
"""

# 不带参任务  可以通过 http://127.0.0.1:8000/apis/celerytest/task_test 将此任务放到管道中去
@app.task()
def task1():
    print("no args task")
    name="sc_"+str(random.random())
    Group.objects.create(name=name)
    return BaseApi.api_ajax_success({"data": name}, "cytasks.tasks.task1")

# 带参数  
@app.task()
def task2(p1,p2):
    try:
        data = School.objects.filter(Q(status=1)).values()[0:5]
        print("cytasks.tasks.task2",{'p1':p1,'p2':p2,'data':data},)
        return BaseApi.api_ajax_success({"data": list(data)}, "cytasks.tasks.task2")
    except:
      print('Something went wrong')

"""
    异常测试  任务名称必须保证唯一
    name 任务名称
    bind 任务content
    typing 是否检测任务参数，如果是true 则在任务进行 前检任务传递的参数是否一致。不一致报异常 （如果是False 不管参数是否一致都不报异常）

"""
@app.task(name='cytasks.tasks.task3_rename',bind=True,typing=False)
def task3(self):
    try:
        print("task id:{0},has retries:{1}".format(self.request.id,self.request.retries)) #已重复的次数
        data = School.objects.create(name="x",num1='1629790539.92852987') # 会抛出一个异常
        return BaseApi.api_ajax_success({"data": "data"}, "cytasks.tasks.task3")
    except MemoryError as exc:
        raise exceptions.Reject(exc, requeue=False)    # 如果出现内存 则抛出异常 并且停止重试
    except Exception as exc:
      print('Something went wrong')
      """
        任务异常时重复执行
        countdown  x秒后执行
        max_retries 重复执行次数
        exc 异常报告
      """
      self.retry(countdown=5,max_retries=3,exc=exc)   


class MyTask(Task):
    def on_failure(self, exc, task_id, args, kwargs, einfo):
        print('{0!r} ----failed----: {1!r}'.format(task_id, exc))

"""
    base  指定任务基类,              
    throws 遇到指定异常时 抛出异常
    max_retries 最大重复次数，如果抛出了异常 则不重复了
"""
# 
@app.task(base=MyTask,throws=(KeyError,Http404),max_retries=3)
def task4():
    print("指定任务基类")
    raise ZeroDivisionError()
   

# celery.py 的 app.conf.update 会将此方法 放到管道中  并且定时触发
@shared_task
def task_schedule(x, y):
    time.sleep(3)
    print("cytasks.tasks.task_schedule", x, y)
    return 0

"""
    如果一个任务条件 关联了多个任务的结果，则需要链式调用
"""
def update_page_info(url):
    # fetch_page -> parse_page -> store_page
    chain = fetch_page.s(url) | parse_page.s() | store_page_info.s(url)
    chain()

@app.task()
def fetch_page(url):
    return requests.get(url)

@app.task()
def parse_page(page):
    return requests.parse_document(page)

@app.task(ignore_result=True)
def store_page_info(info, url):
    School.objects.create(url=url, info=info)
